﻿using CaltechSoft.Service.DBCommand;
using CaltechSoft.Service.EntityFW.Entity;
using CaltechSoft.Service.EntityFW.Repository;
using CaltechSoft.Service.Infrastructure.Utility;
using CaltechSoft.Service.ReportService;
using System;
using System.Data.Entity;
using System.Linq;


namespace CaltechSoft.Service.CommandService
{
    public class CertificateCommandService : ICertificateCommandService
    {
        private readonly IUnitOfWork _unitOfWork;

        private readonly ICertificateStandardCommandService _certificateStandardCommandService;
        private readonly IEquipmentCommandService _equipmentCommandService;
        private readonly ICustomerCommandService _customerCommandService;
        private readonly ICertificateDetailsCommandService _certificateDetailsCommandService;
        private readonly ICertificateReportService _certificateReportService;

        private readonly IGenericRepository<CertificateDetails> _certificateDetailsGenericRepository;
        private readonly IGenericRepository<CertificateStandard> _certificateStandardGenericRepository;


        public CertificateCommandService(IUnitOfWork unitOfWork, ICertificateStandardCommandService certificateStandardCommandService,
                                         IEquipmentCommandService equipmentCommandService, ICustomerCommandService customerCommandService,
                                         ICertificateDetailsCommandService certificateDetailsCommandService,
                                         IGenericRepository<CertificateDetails> certificateDetailsGenericRepository,
                                         IGenericRepository<CertificateStandard> certificateStandardGenericRepository,
                                         ICertificateReportService certificateReportService)
        {
            _unitOfWork = unitOfWork;
            _certificateStandardCommandService = certificateStandardCommandService;
            _equipmentCommandService = equipmentCommandService;
            _customerCommandService = customerCommandService;
            _certificateDetailsCommandService = certificateDetailsCommandService;
            _certificateStandardGenericRepository = certificateStandardGenericRepository;
            _certificateDetailsGenericRepository = certificateDetailsGenericRepository;
            _certificateReportService = certificateReportService;
        }

        public int CreateNewCertificate(CreateNewCertificateCommand command)
        {
            Guard.ArgumentIsNotNull(command, "command");
            Guard.Against<ArgumentException>(command.Customer.Id < 1, "Customer can not be empty");

            var certificate = new Certificate();

            //int equipmentId = _equipmentCommandService.CreateEquipment(new CreateEquipmentCommand()
            //{
            //    AssetNumber = command.AssetNumber,
            //    Procedure = command.Procedure,
            //    Description = command.Description,
            //    Manufacturer = command.Manufacturer,
            //    ModelNumber = command.ModelNumber,
            //    PONumber = command.PoNumber,
            //    SerialNumber = command.SerialNumber,
            //    CreatedDate = command.CreatedDate
            //});

            certificate.CustomerId = command.Customer.Id;
            //certificate.EquipmentId = command.e;
            GenerateCertificate(ref certificate, command);

            _unitOfWork.Repository<Certificate>().Insert(certificate);
            _unitOfWork.Save();
            var certificateId = certificate.CertificateId;

            foreach (var certStandard in command.Standards)
            {
                var certId = _certificateStandardCommandService.CreateCertificateStandard(new CreateCertificateStandardCommand()
                {
                    StandardNo = certStandard.StandardNo,
                    DueDate = certStandard.DueDate ?? DateTime.Now,
                    Manufacturer = certStandard.Manufacturer,
                    ModelNumber = certStandard.ModelNumber,
                    TestReportNumber = certStandard.TestReportNumber
                });

                _certificateDetailsCommandService.CreateCertificateDetails(certificateId, certId);
            }

            return certificateId;
        }

        public int UpdateCertificate(int certId, CreateNewCertificateCommand command)
        {
            Guard.ArgumentIsNotNull(command, "command");
            Guard.ArgumentIsNotNull(command.Customer.Id < 1, "Customer is invalid!");

            var certificate = new Certificate();
            certificate.CertificateId = certId;

            //int equipmentId = _equipmentCommandService.CreateEquipment(new CreateEquipmentCommand()
            //{
            //    AssetNumber = command.AssetNumber,
            //    Procedure = command.Procedure,
            //    Description = command.Description,
            //    Manufacturer = command.Manufacturer,
            //    ModelNumber = command.ModelNumber,
            //    PONumber = command.PoNumber,
            //    SerialNumber = command.SerialNumber,
            //    CreatedDate = command.CreatedDate
            //});

            certificate.CustomerId = command.Customer.Id;
            //certificate.EquipmentId = equipmentId;
            GenerateCertificate(ref certificate, command, false);

            _unitOfWork.Repository<Certificate>().Update(certificate);
            _unitOfWork.Save();
            var certificateId = certificate.CertificateId;

            #region remove standard redundant
            var certificateDetails = _certificateDetailsGenericRepository.Get(n => n.CertificateId == certId);
            var listMainIds = command.Standards.Select(n => n.CertificateStandardId);
            var certificateStandards = _certificateStandardGenericRepository.Get(n => listMainIds.Contains(n.CertificateStandardId));
            var removeStandards = certificateDetails.Where(n => !listMainIds.Contains(n.CertificateStandardId));
            foreach (var remove in removeStandards)
            {
                _unitOfWork.Repository<CertificateDetails>().Delete(remove.CertificateDetailsId);
                _unitOfWork.Save();
            }
            #endregion

            #region add/update standard
            foreach (var certStandard in command.Standards)
            {
                Guard.Against<Exception>(!(certStandard.CertificateStandardId > 0), "Can not update certificate with standard manufacturer " + certStandard.Manufacturer);
                _certificateDetailsCommandService.CreateCertificateDetails(certificateId, certStandard.CertificateStandardId.Value);
            }
            #endregion

            return certificateId;
        }


        public void Delete(int certificateId)
        {
            var certificateDetails = _certificateDetailsGenericRepository.Get(n => n.CertificateId == certificateId);
            foreach (var item in certificateDetails)
            {
                _unitOfWork.Repository<CertificateDetails>().Delete(item.CertificateDetailsId);
                _unitOfWork.Save();
            }
            _unitOfWork.Repository<Certificate>().Delete(certificateId);
            _unitOfWork.Save();
        }

        private void GenerateCertificate(ref Certificate certificate, CreateNewCertificateCommand command, bool isCreate = true)
        {
            certificate.CertificateNo = GenerateCertificateNo(command.CertificateNo);
            certificate.WorkOrderNo = command.WorkOrderNo;

            certificate.CalibrationCycle = command.CalibrationCycle;
            certificate.CalibrationDate = command.CalibrationDate ?? DateTime.Now;
            certificate.CertifiedBy = command.CertifiedBy;
            certificate.ConditionReceivedId = command.ConditionReceivedId.ToString();
            certificate.ConditionReturnedId = command.ConditionReturnedId.ToString();

            if (isCreate)
            {
                certificate.CreatedBy = string.IsNullOrWhiteSpace(command.CreatedBy) ? "" : command.CreatedBy;
                certificate.CreatedDate = DateTime.Now;
            }
            else
            {
                certificate.UpdatedBy = string.IsNullOrWhiteSpace(command.CreatedBy) ? "" : command.CreatedBy;
                certificate.UpdatedDate = DateTime.Now;
            }

            certificate.NextDueDate = command.NextDueDate ?? DateTime.Now;
            certificate.RelativeHumidity = command.RelativeHumidity;
            certificate.Temperature = command.Temperature;

            certificate.Manufacturer = command.Manufacturer;
            certificate.Description = command.Description;
            certificate.ModelNumber = command.ModelNumber;
            certificate.SerialNumber = command.SerialNumber;
            certificate.PONumber = command.PoNumber;
            certificate.Procedure = command.Procedure;
            certificate.AssetNumber = command.AssetNumber;

            certificate.Technician = command.Technician;
            certificate.QualityInspector = command.Inspector;
            certificate.Remarks = command.Remarks;
            certificate.ApprovedBy = command.ApprovedBy;
        }

        private string GenerateCertificateNo(string certificateNo)
        {
            #region generate certNo
            try
            {
                var newCertNo = "C" + DateTime.Now.ToString("MMddyy") + "-";
                if (string.IsNullOrWhiteSpace(certificateNo))
                {
                    var lastCertificate = _certificateReportService.Search(new SearchCriteria.CertificateSearchCriteria(), 1, 0).Items.FirstOrDefault();
                    if (lastCertificate != null)
                    {
                        if (lastCertificate.CreatedDate.Date == DateTime.Now.Date && !string.IsNullOrWhiteSpace(lastCertificate.CertificateNo))
                        {
                            var orderNo = lastCertificate.CertificateNo.Split('-');
                            return newCertNo += (Convert.ToInt32(orderNo.LastOrDefault()) + 1).ToString("0000");
                        }
                        else
                        {
                            return newCertNo += (1).ToString("0000");
                        }
                    }
                    return newCertNo += (1).ToString("0000");
                }
                return certificateNo;
            }
            catch (Exception)
            {
                return "";
            }
            #endregion
        }



    }
}
